home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 2 / Apprentice-Release2.iso / Source Code / C / Games / NetHack 3.1.3 / source / src / files.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-08-01  |  23.9 KB  |  1,140 lines  |  [TEXT/R*ch]

  1. /*    SCCS Id: @(#)files.c    3.1    93/06/27    */
  2. /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
  3. /* NetHack may be freely redistributed.  See license for details. */
  4.  
  5. #include "hack.h"
  6.  
  7. #include <ctype.h>
  8.  
  9. #if !defined(MAC) && !defined(O_WRONLY) && !defined(AZTEC_C)
  10. #include <fcntl.h>
  11. #endif
  12. #if defined(UNIX) || defined(VMS)
  13. #include <errno.h>
  14. # ifndef SKIP_ERRNO
  15. extern int errno;
  16. # endif
  17. #include <signal.h>
  18. #endif
  19.  
  20. #if defined(MSDOS) || defined(OS2) || defined(TOS) || defined(WIN32)
  21. # ifndef GNUDOS
  22. #include <sys\stat.h>
  23. # else
  24. #include <sys/stat.h>
  25. # endif
  26. #endif
  27. #ifndef O_BINARY    /* used for micros, no-op for others */
  28. # define O_BINARY 0
  29. #endif
  30.  
  31. #ifdef MFLOPPY
  32. char bones[FILENAME];        /* pathname of bones files */
  33. char lock[FILENAME];        /* pathname of level files */
  34. #else
  35. static char bones[] = "bonesnn.xxxx";
  36. # ifdef VMS
  37. char lock[PL_NSIZ+17] = "1lock"; /* long enough for _uid+name+.99;1 */
  38. # else
  39. char lock[PL_NSIZ+14] = "1lock"; /* long enough for uid+name+.99 */
  40. # endif
  41. #endif
  42.  
  43. #ifdef MAC
  44. #include <files.h>
  45. MacDirs theDirs ;
  46. #endif
  47.  
  48. #ifdef UNIX
  49. #define SAVESIZE    (PL_NSIZ + 13)    /* save/99999player.e */
  50. #else
  51. # ifdef VMS
  52. #define SAVESIZE    (PL_NSIZ + 22)    /* [.save]<uid>player.e;1 */
  53. # else
  54. #define SAVESIZE    FILENAME    /* from macconf.h or pcconf.h */
  55. # endif
  56. #endif
  57.  
  58. char SAVEF[SAVESIZE];    /* holds relative path of save file from playground */
  59. #ifdef MICRO
  60. char SAVEP[SAVESIZE];    /* holds path of directory for save file */
  61. #endif
  62. #ifdef AMIGA
  63. extern char PATH[];    /* see sys/amiga/amidos.c */
  64. #endif
  65.  
  66. extern int n_dgns;        /* from dungeon.c */
  67.  
  68. static char * FDECL(set_bonesfile_name, (char *,d_level*));
  69.  
  70. /* fopen a file, with OS-dependent bells and whistles */
  71. FILE *
  72. fopen_datafile(filename, mode)
  73. const char *filename, *mode;
  74. {
  75.     FILE *fp;
  76. #ifdef AMIGA
  77.     fp = fopenp(filename, mode);
  78. #else
  79. # ifdef VMS    /* essential to have punctuation, to avoid logical names */
  80.     char tmp[BUFSIZ];
  81.  
  82.     if (!index(filename, '.') && !index(filename, ';'))
  83.         filename = strcat(strcpy(tmp, filename), ";0");
  84.     fp = fopen(filename, mode, "mbc=16");
  85. # else
  86.     fp = fopen(filename, mode);
  87. # endif
  88. #endif
  89.     return fp;
  90. }
  91.  
  92.  
  93. /* ----------  BEGIN LEVEL FILE HANDLING ----------- */
  94.  
  95. #ifdef MFLOPPY
  96. /* Set names for bones[] and lock[] */
  97. void
  98. set_lock_and_bones()
  99. {
  100.     if (!ramdisk) {
  101.         Strcpy(levels, permbones);
  102.         Strcpy(bones, permbones);
  103.     }
  104.     append_slash(permbones);
  105.     append_slash(levels);
  106.     append_slash(bones);
  107.     Strcat(bones, "bonesnn.*");
  108.     Strcpy(lock, levels);
  109.     Strcat(lock, alllevels);
  110.     return;
  111. }
  112. #endif /* MFLOPPY */
  113.  
  114.  
  115. /* Construct a file name for a level-type file, which is of the form
  116.  * something.level (with any old level stripped off).
  117.  * This assumes there is space on the end of 'file' to append
  118.  * a two digit number.  This is true for 'level'
  119.  * but be careful if you use it for other things -dgk
  120.  */
  121. void
  122. set_levelfile_name(file, lev)
  123. char *file;
  124. int lev;
  125. {
  126.     char *tf;
  127.  
  128.     tf = rindex(file, '.');
  129.     if (!tf) tf = eos(file);
  130.     Sprintf(tf, ".%d", lev);
  131. #ifdef VMS
  132.     Strcat(tf, ";1");
  133. #endif
  134.     return;
  135. }
  136.  
  137. int
  138. create_levelfile(lev)
  139. int lev;
  140. {
  141.     int fd;
  142.  
  143.     set_levelfile_name(lock, lev);
  144.  
  145. #if defined(MICRO)
  146.     /* Use O_TRUNC to force the file to be shortened if it already
  147.      * exists and is currently longer.
  148.      */
  149.     fd = open(lock, O_WRONLY |O_CREAT | O_TRUNC | O_BINARY, FCMASK);
  150. #else
  151. # ifdef MAC
  152.     fd = maccreat(lock, LEVL_TYPE);
  153. # else
  154.     fd = creat(lock, FCMASK);
  155. # endif
  156. #endif /* MICRO */
  157.  
  158.     return fd;
  159. }
  160.  
  161.  
  162. int
  163. open_levelfile(lev)
  164. int lev;
  165. {
  166.     int fd;
  167.  
  168.     set_levelfile_name(lock, lev);
  169. #ifdef MFLOPPY
  170.     /* If not currently accessible, swap it in. */
  171.     if (fileinfo[lev].where != ACTIVE)
  172.         swapin_file(lev);
  173. #endif
  174. #ifdef MAC
  175.     fd = macopen(lock, O_RDONLY | O_BINARY, LEVL_TYPE);
  176. #else
  177.     fd = open(lock, O_RDONLY | O_BINARY, 0);
  178. #endif
  179.     return fd;
  180. }
  181.  
  182.  
  183. void
  184. delete_levelfile(lev)
  185. int lev;
  186. {
  187.     set_levelfile_name(lock, lev);
  188.     (void) unlink(lock);
  189. }
  190.  
  191.  
  192. void
  193. clearlocks()
  194. {
  195. #ifdef MFLOPPY
  196.     eraseall(levels, alllevels);
  197. # ifndef AMIGA
  198.     if (ramdisk)
  199.         eraseall(permbones, alllevels);
  200. # endif
  201. #else
  202.     register int x;
  203.  
  204. # if defined(UNIX) || defined(VMS)
  205.     (void) signal(SIGHUP, SIG_IGN);
  206. # endif
  207.     /* can't access maxledgerno() before dungeons are created -dlc */
  208.     for (x = (n_dgns ? maxledgerno() : 0); x >= 0; x--)
  209.         delete_levelfile(x);    /* not all levels need be present */
  210. #endif
  211. }
  212.  
  213. /* ----------  END LEVEL FILE HANDLING ----------- */
  214.  
  215.  
  216. /* ----------  BEGIN BONES FILE HANDLING ----------- */
  217.  
  218. static char *
  219. set_bonesfile_name(file, lev)
  220. char *file;
  221. d_level *lev;
  222. {
  223.     char *dptr = rindex(file, '.');
  224.     s_level *sptr;
  225.  
  226.     if (!dptr) dptr = eos(file);
  227.     *(dptr-2) = dungeons[lev->dnum].boneid;
  228. #ifdef MULDGN
  229.     *(dptr-1) = In_quest(lev) ? pl_character[0] : '0';
  230. #else
  231.     *(dptr-1) = '0';
  232. #endif
  233.     if ((sptr = Is_special(lev)) != 0)
  234.         Sprintf(dptr, ".%c", sptr->boneid);
  235.     else
  236.         Sprintf(dptr, ".%d", lev->dlevel);
  237. #ifdef VMS
  238.     Strcat(dptr, ";1");
  239. #endif
  240.     return(dptr-2);
  241. }
  242.  
  243. int
  244. create_bonesfile(lev, bonesid)
  245. d_level *lev;
  246. char **bonesid;
  247. {
  248.     int fd;
  249.  
  250.     *bonesid = set_bonesfile_name(bones, lev);
  251.  
  252. #ifdef MICRO
  253.     /* Use O_TRUNC to force the file to be shortened if it already
  254.      * exists and is currently longer.
  255.      */
  256.     fd = open(bones, O_WRONLY |O_CREAT | O_TRUNC | O_BINARY, FCMASK);
  257. #else
  258. # ifdef MAC
  259.     fd = maccreat(bones, BONE_TYPE);
  260. # else
  261.     fd = creat(bones, FCMASK);
  262. # endif
  263. # if defined(VMS) && !defined(SECURE)
  264.     /*
  265.        Re-protect bones file with world:read+write+execute+delete access.
  266.        umask() doesn't seem very reliable; also, vaxcrtl won't let us set
  267.        delete access without write access, which is what's really wanted.
  268.        Can't simply create it with the desired protection because creat
  269.        ANDs the mask with the user's default protection, which usually
  270.        denies some or all access to world.
  271.      */
  272.     (void) chmod(bones, FCMASK | 007);  /* allow other users full access */
  273. # endif /* VMS && !SECURE */
  274. #endif /* MICRO */
  275.  
  276.     return fd;
  277. }
  278.  
  279.  
  280. int
  281. open_bonesfile(lev, bonesid)
  282. d_level *lev;
  283. char **bonesid;
  284. {
  285.     int fd;
  286.  
  287.     *bonesid = set_bonesfile_name(bones, lev);
  288.     uncompress(bones);    /* no effect if nonexistent */
  289. #ifdef MAC
  290.     fd = macopen(bones, O_RDONLY | O_BINARY, BONE_TYPE);
  291. #else
  292.     fd = open(bones, O_RDONLY | O_BINARY, 0);
  293. #endif
  294.     return fd;
  295. }
  296.  
  297.  
  298. int
  299. delete_bonesfile(lev)
  300. d_level *lev;
  301. {
  302.     (void) set_bonesfile_name(bones, lev);
  303.     return !(unlink(bones) < 0);
  304. }
  305.  
  306.  
  307. /* assume we're compressing the recently read or created bonesfile, so the
  308.  * file name is already set properly */
  309. void
  310. compress_bonesfile()
  311. {
  312.     compress(bones);
  313. }
  314.  
  315. /* ----------  END BONES FILE HANDLING ----------- */
  316.  
  317.  
  318. /* ----------  BEGIN SAVE FILE HANDLING ----------- */
  319.  
  320. /* set savefile name in OS-dependent manner from pre-existing plname,
  321.  * avoiding troublesome characters */
  322. void
  323. set_savefile_name()
  324. {
  325. #ifdef VMS
  326.     Sprintf(SAVEF, "[.save]%d%s", getuid(), plname);
  327.     regularize(SAVEF+7);
  328.     Strcat(SAVEF, ";1");
  329. #else
  330. # ifdef MICRO
  331.     Strcpy(SAVEF, SAVEP);
  332.     {
  333.         int i = strlen(SAVEP);
  334. #  ifdef AMIGA
  335.         /* plname has to share space with SAVEP and ".sav" */
  336.         (void)strncat(SAVEF, plname, FILENAME - i - 4);
  337. #  else
  338.         (void)strncat(SAVEF, plname, 8);
  339. #  endif
  340.         regularize(SAVEF+i);
  341.     }
  342.     Strcat(SAVEF, ".sav");
  343. # else
  344.     Sprintf(SAVEF, "save/%d%s", (int)getuid(), plname);
  345.     regularize(SAVEF+5);    /* avoid . or / in name */
  346. # endif    /* MICRO */
  347. #endif    /* VMS */
  348. }
  349.  
  350. #ifdef INSURANCE
  351. void
  352. save_savefile_name(fd)
  353. int fd;
  354. {
  355.     (void) write(fd, (genericptr_t) SAVEF, sizeof(SAVEF));
  356. }
  357. #endif
  358.  
  359.  
  360. #if defined(WIZARD) && !defined(MICRO)
  361. /* change pre-existing savefile name to indicate an error savefile */
  362. void
  363. set_error_savefile()
  364. {
  365. # ifdef VMS
  366.       {
  367.     char *semi_colon = rindex(SAVEF, ';');
  368.     if (semi_colon) *semi_colon = '\0';
  369.       }
  370.     Strcat(SAVEF, ".e;1");
  371. # else
  372. #  ifdef MAC
  373.     Strcat(SAVEF, "-e");
  374. #  else
  375.     Strcat(SAVEF, ".e");
  376. #  endif
  377. # endif
  378. }
  379. #endif
  380.  
  381.  
  382. /* create save file, overwriting one if it already exists */
  383. int
  384. create_savefile()
  385. {
  386.     int fd;
  387. #ifdef AMIGA
  388.     fd = ami_wbench_getsave(O_WRONLY | O_CREAT | O_TRUNC);
  389. #else
  390. # ifdef MICRO
  391.     fd = open(SAVEF, O_WRONLY | O_BINARY | O_CREAT | O_TRUNC, FCMASK);
  392. # else
  393. #  ifdef MAC
  394.     fd = maccreat(SAVEF, SAVE_TYPE);
  395. #  else
  396.     fd = creat(SAVEF, FCMASK);
  397. #  endif
  398. #  if defined(VMS) && !defined(SECURE)
  399.     /*
  400.        Make sure the save file is owned by the current process.  That's
  401.        the default for non-privileged users, but for priv'd users the
  402.        file will be owned by the directory's owner instead of the user.
  403.      */
  404. #   ifdef getuid    /*(see vmsunix.c)*/
  405. #    undef getuid
  406. #   endif
  407.     (void) chown(SAVEF, getuid(), getgid());
  408. #  endif /* VMS && !SECURE */
  409. # endif    /* MICRO */
  410. #endif    /* AMIGA */
  411.  
  412.     return fd;
  413. }
  414.  
  415.  
  416. /* open savefile for reading */
  417. int
  418. open_savefile()
  419. {
  420.     int fd;
  421.  
  422. #ifdef AMIGA
  423.     fd = ami_wbench_getsave(O_RDONLY);
  424. #else
  425. # ifdef MAC
  426.     fd = macopen(SAVEF, O_RDONLY | O_BINARY, SAVE_TYPE);
  427. # else
  428.     fd = open(SAVEF, O_RDONLY | O_BINARY, 0);
  429. # endif
  430. #endif /* AMIGA */
  431.     return fd;
  432. }
  433.  
  434.  
  435. /* delete savefile */
  436. int
  437. delete_savefile()
  438. {
  439. #ifdef AMIGA
  440.     ami_wbench_unlink(SAVEF);
  441. #endif
  442.     (void) unlink(SAVEF);
  443.     return 0;    /* for xxxmain.c test */
  444. }
  445.  
  446.  
  447. /* ----------  END SAVE FILE HANDLING ----------- */
  448.  
  449.  
  450. /* ----------  BEGIN FILE COMPRESSION HANDLING ----------- */
  451.  
  452. #ifdef COMPRESS
  453. /* 
  454.  * using system() is simpler, but opens up security holes and causes
  455.  * problems on at least Interactive UNIX 3.0.1 (SVR3.2), where any
  456.  * setuid is renounced by /bin/sh, so the files cannot be accessed.
  457.  *
  458.  * cf. child() in unixunix.c.
  459.  */
  460. void
  461. docompress_file(filename, uncomp)
  462. char *filename;
  463. boolean uncomp;
  464. {
  465.     char *args[10];
  466. # ifdef COMPRESS_OPTIONS
  467.     char opts[80];
  468. # endif
  469.     int i = 0;
  470.     int f;
  471.  
  472.     args[0] = COMPRESS;
  473.     if (uncomp) args[++i] = "-d";    /* uncompress */
  474. # ifdef COMPRESS_OPTIONS
  475.     {
  476.         /* we can't guarantee there's only one additional option, sigh */
  477.         char *opt;
  478.         boolean inword = FALSE;
  479.  
  480.         Strcpy(opts, COMPRESS_OPTIONS);
  481.         opt = opts;
  482.         while (*opt) {
  483.         if ((*opt == ' ') || (*opt == '\t')) {
  484.             if (inword) {
  485.             *opt = '\0';
  486.             inword = FALSE;
  487.             }
  488.         } else if (!inword) {
  489.             args[++i] = opt;
  490.             inword = TRUE;
  491.         }
  492.         opt++;
  493.         }
  494.     }
  495. # endif
  496.     args[++i] = filename;
  497.     args[++i] = NULL;
  498.  
  499.     f = fork();
  500.     if (f == 0) {    /* child */
  501.         (void) execv(args[0], args);
  502.         perror(NULL);
  503.         pline("Exec to %scompress %s failed.",
  504.             uncomp ? "un" : "", filename);
  505.         exit(1);
  506.     } else if (f == -1) {
  507.         perror(NULL);
  508.         pline("Fork to %scompress %s failed.",
  509.             uncomp ? "un" : "", filename);
  510.         return;
  511.     }
  512.     (void) signal(SIGINT, SIG_IGN);
  513.     (void) signal(SIGQUIT, SIG_IGN);
  514.     (void) wait((int *)0);
  515.     (void) signal(SIGINT, (SIG_RET_TYPE) done1);
  516. # ifdef WIZARD
  517.     if (wizard) (void) signal(SIGQUIT, SIG_DFL);
  518. # endif
  519. }
  520. #endif
  521.  
  522. /* compress file */
  523. void
  524. compress(filename)
  525. const char *filename;
  526. #ifdef applec
  527. # pragma unused(filename)
  528. #endif
  529. {
  530. #ifdef COMPRESS
  531.     docompress_file(filename, FALSE);
  532. #endif
  533. }
  534.  
  535.  
  536. /* uncompress file if it exists */
  537. void
  538. uncompress(filename)
  539. const char *filename;
  540. #ifdef applec
  541. # pragma unused(filename)
  542. #endif
  543. {
  544. #ifdef COMPRESS
  545.     char cfn[80];
  546.     int fd;
  547.  
  548.     Strcpy(cfn, filename);
  549. # ifdef COMPRESS_EXTENSION
  550.     Strcat(cfn, COMPRESS_EXTENSION);
  551. # endif
  552.     if ((fd = open(cfn, O_RDONLY)) >= 0) {
  553.         (void) close(fd);
  554.         docompress_file(cfn, TRUE);
  555.     }
  556. #endif
  557. }
  558.  
  559. /* ----------  END FILE COMPRESSION HANDLING ----------- */
  560.  
  561.  
  562. /* ----------  BEGIN FILE LOCKING HANDLING ----------- */
  563.  
  564. #ifdef NO_FILE_LINKS    /* implies UNIX */
  565. static int lockfd;    /* for lock_file() to pass to unlock_file() */
  566. #endif
  567.  
  568. #if defined(UNIX) || defined(VMS)
  569. #define HUP    if(!done_hup)
  570.  
  571. static char *
  572. make_lockname(filename)
  573. const char *filename;
  574. {
  575.     static char lockname[BUFSZ];
  576.  
  577. # ifdef NO_FILE_LINKS
  578.     Strcpy(lockname, LOCKDIR);
  579.     Strcat(lockname, "/");
  580.     Strcat(lockname, filename);
  581. # else
  582.     Strcpy(lockname, filename);
  583. # endif
  584. # ifdef VMS
  585.       {
  586.     char *semi_colon = rindex(lockname, ';');
  587.     if (semi_colon) *semi_colon = '\0';
  588.       }
  589.     Strcat(lockname, ".lock;1");
  590. # else
  591.     Strcat(lockname, "_lock");
  592. # endif
  593.     return lockname;
  594. }
  595. #endif  /* UNIX || VMS */
  596.  
  597.  
  598. /* lock a file */
  599. boolean
  600. lock_file(filename, retryct)
  601. const char *filename;
  602. int retryct;
  603. #ifdef applec
  604. # pragma unused(filename, retryct)
  605. #endif
  606. {
  607. #if defined(UNIX) || defined(VMS)
  608.     char *lockname;
  609.  
  610.     lockname = make_lockname(filename);
  611.  
  612. # ifdef NO_FILE_LINKS
  613.     while ((lockfd = open(lockname, O_RDWR|O_CREAT|O_EXCL, 0666)) == -1) {
  614. # else
  615.     while (link(filename, lockname) == -1) {
  616. # endif
  617.         register int errnosv = errno;
  618.  
  619.         switch (errnosv) {    /* George Barbanis */
  620.             case ENOENT:
  621.             HUP raw_printf("Can't find file %s to lock!", filename);
  622.             return FALSE;
  623.             case EACCES:
  624.             HUP raw_printf("No write permission to lock %s!",
  625.                        filename);
  626.             return FALSE;
  627. # ifdef VMS            /* c__translate(vmsfiles.c) */
  628.             case EPERM:
  629.             /* could be misleading, but usually right */
  630.             HUP raw_printf(
  631.                   "Can't lock %s due to directory protection.",
  632.                        filename);
  633.             return FALSE;
  634. # endif
  635.             case EEXIST:
  636.             break;    /* retry checks below */
  637.             default:
  638.             HUP perror(lockname);
  639.             HUP raw_printf(
  640.                      "Cannot lock %s for unknown reason (%d).",
  641.                        filename, errnosv);
  642.             return FALSE;
  643.         }
  644.  
  645.         if (!retryct--) {
  646.             HUP (void) raw_print("I give up.  Sorry.");
  647.             HUP raw_printf("Perhaps there is an old %s around?",
  648.                        lockname);
  649.             return FALSE;
  650.         }
  651.  
  652.         HUP raw_printf("Waiting for access to %s.  (%d retries left).",
  653.                    filename, retryct);
  654. # if defined(SYSV) || defined(ULTRIX) || defined(VMS)
  655.         (void)
  656. # endif
  657.             sleep(1);
  658.     }
  659. #endif  /* UNIX || VMS */
  660.     return TRUE;
  661. }
  662.  
  663.  
  664. #ifdef VMS    /* for unlock_file, use the unlink() routine in vmsunix.c */
  665. # ifdef unlink
  666. #  undef unlink
  667. # endif
  668. # define unlink(foo) vms_unlink(foo)
  669. #endif
  670.  
  671. /* unlock file, which must be currently locked by lock_file */
  672. void
  673. unlock_file(filename)
  674. const char *filename;
  675. #if defined(applec)
  676. # pragma unused(filename)
  677. #endif
  678. {
  679. #if defined(UNIX) || defined(VMS)
  680.     char *lockname;
  681.  
  682.     lockname = make_lockname(filename);
  683.  
  684.     if (unlink(lockname) < 0)
  685.         HUP raw_printf("Can't unlink %s.", lockname);
  686. # ifdef NO_FILE_LINKS
  687.     (void) close(lockfd);
  688. # endif
  689.  
  690. #endif  /* UNIX || VMS */
  691. }
  692.  
  693. /* ----------  END FILE LOCKING HANDLING ----------- */
  694.  
  695.  
  696. /* ----------  BEGIN CONFIG FILE HANDLING ----------- */
  697.  
  698. const char *configfile =
  699. #ifdef UNIX
  700.             ".nethackrc";
  701. #else
  702. # ifdef MAC
  703.             "NetHack defaults";
  704. # else
  705.             "NetHack.cnf";
  706. # endif
  707. #endif
  708.  
  709. static FILE *FDECL(fopen_config_file, (const char *));
  710. static int FDECL(get_uchars, (FILE *, char *, char *, uchar *, int, const char *));
  711. int FDECL(parse_config_line, (FILE *, char *, char *, char *));
  712.  
  713. #ifndef MFLOPPY
  714. #define fopenp fopen
  715. #endif
  716.  
  717. static FILE *
  718. fopen_config_file(filename)
  719. const char *filename;
  720. {
  721.     FILE *fp;
  722. #if defined(UNIX) || defined(VMS)
  723.     char    tmp_config[BUFSZ];
  724. #endif
  725.  
  726.     /* "filename" is an environment variable, so it should hang around */
  727.     if (filename) {
  728. #ifdef UNIX
  729.         if (access(filename, 4) == -1) {
  730.             /* 4 is R_OK on newer systems */
  731.             /* nasty sneaky attempt to read file through
  732.              * NetHack's setuid permissions -- this is the only
  733.              * place a file name may be wholly under the player's
  734.              * control
  735.              */
  736.             raw_printf("Access to %s denied (%d).",
  737.                     filename, errno);
  738.             wait_synch();
  739.             /* fall through to standard names */
  740.         } else
  741. #endif
  742.         if ((fp = fopenp(filename, "r")) != (FILE *)0) {
  743.             configfile = filename;
  744.             return(fp);
  745.         }
  746.     }
  747.  
  748. #if defined(MICRO) || defined(MAC)
  749.     if ((fp = fopenp(configfile, "r")) != (FILE *)0)
  750.         return(fp);
  751. #else
  752. # ifdef VMS
  753.     if ((fp = fopenp("nethackini", "r")) != (FILE *)0) {
  754.         configfile = "nethackini";
  755.         return(fp);
  756.     }
  757.     if ((fp = fopenp("sys$login:nethack.ini", "r")) != (FILE *)0) {
  758.         configfile = "nethack.ini";
  759.         return(fp);
  760.     }
  761.     Sprintf(tmp_config, "%s%s", getenv("HOME"), "NetHack.cnf");
  762.     if ((fp = fopenp(tmp_config, "r")) != (FILE *)0)
  763.         return(fp);
  764. # else    /* should be only UNIX left */
  765.     Sprintf(tmp_config, "%s/%s", getenv("HOME"), ".nethackrc");
  766.     if ((fp = fopenp(tmp_config, "r")) != (FILE *)0)
  767.         return(fp);
  768. # endif
  769. #endif
  770.     return (FILE *)0;
  771.  
  772. }
  773.  
  774.  
  775. /*
  776.  * Retrieve a list of integers from a file into a uchar array.
  777.  *
  778.  * NOTE:  This routine is unable to read a value of 0.
  779.  */
  780. static int
  781. get_uchars(fp, buf, bufp, list, size, name)
  782.     FILE *fp;        /* input file pointer */
  783.     char *buf;        /* read buffer, must be of size BUFSZ */
  784.     char *bufp;        /* current pointer */
  785.     uchar *list;    /* return list */
  786.     int  size;        /* return list size */
  787.     const char *name;        /* name of option for error message */
  788. {
  789.     unsigned int num = 0;
  790.     int count = 0;
  791.  
  792.     while (1) {
  793.     switch(*bufp) {
  794.         case ' ':  case '\0':
  795.         case '\t': case '\n':
  796.         if (num) {
  797.             list[count++] =  num;
  798.             num = 0;
  799.         }
  800.         if (count == size || !*bufp) return count;
  801.         bufp++;
  802.         break;
  803.  
  804.         case '0': case '1': case '2': case '3':
  805.         case '4': case '5': case '6': case '7':
  806.         case '8': case '9':
  807.         num = num*10 + (*bufp-'0');
  808.         bufp++;
  809.         break;
  810.  
  811.         case '\\':
  812.             if (fp == (FILE *)0)
  813.             goto gi_error;
  814.         do  {
  815.             if (!fgets(buf, BUFSZ, fp)) goto gi_error;
  816.         } while (buf[0] == '#');
  817.         bufp = buf;
  818.         break;
  819.  
  820.         default:
  821. gi_error:
  822.         raw_printf("Syntax error in %s", name);
  823.         wait_synch();
  824.         return count;
  825.     }
  826.     }
  827.     /*NOTREACHED*/
  828. }
  829.  
  830. /*ARGSUSED*/
  831. int
  832. parse_config_line(fp, buf, tmp_ramdisk, tmp_levels)
  833. FILE        *fp;
  834. char        *buf;
  835. char        *tmp_ramdisk;
  836. char        *tmp_levels;
  837. #if defined(applec)
  838. # pragma unused(tmp_ramdisk,tmp_levels)
  839. #endif
  840. {
  841.     char        *bufp, *altp;
  842.  
  843.     if (*buf == '#')
  844.         return 1;
  845.  
  846.     /* remove trailing whitespace */
  847.     bufp = eos(buf);
  848.     while (--bufp > buf && isspace(*bufp))
  849.         continue;
  850.  
  851.     if (bufp <= buf)
  852.         return 1;        /* skip all-blank lines */
  853.     else
  854.         *(bufp + 1) = '\0';    /* terminate line */
  855.  
  856.     /* find the '=' or ':' */
  857.     bufp = index(buf, '=');
  858.     altp = index(buf, ':');
  859.     if (!bufp || (altp && altp < bufp)) bufp = altp;
  860.     if (!bufp) return 0;
  861.  
  862.     /* skip  whitespace between '=' and value */
  863.     do { ++bufp; } while (isspace(*bufp));
  864.  
  865.     /* Go through possible variables */
  866.     if (!strncmpi(buf, "OPTIONS", 4)) {
  867.         parseoptions(bufp, TRUE, TRUE);
  868.         if (plname[0])        /* If a name was given */
  869.             plnamesuffix();    /* set the character class */
  870. #ifdef MICRO
  871.     } else if (!strncmpi(buf, "HACKDIR", 4)) {
  872.         (void) strncpy(hackdir, bufp, PATHLEN);
  873. # ifdef MFLOPPY
  874.     } else if (!strncmpi(buf, "RAMDISK", 3)) {
  875.                 /* The following ifdef is NOT in the wrong
  876.                  * place.  For now, we accept and silently
  877.                  * ignore RAMDISK */
  878. #  ifndef AMIGA
  879.         (void) strncpy(tmp_ramdisk, bufp, PATHLEN);
  880. #  endif
  881. # endif
  882.     } else if (!strncmpi(buf, "LEVELS", 4)) {
  883.         (void) strncpy(tmp_levels, bufp, PATHLEN);
  884.  
  885.     } else if (!strncmpi(buf, "SAVE", 4)) {
  886. # ifdef MFLOPPY
  887.         extern    int saveprompt;
  888. #endif
  889.         char *ptr;
  890.         if (ptr = index(bufp, ';')) {
  891.             *ptr = '\0';
  892. # ifdef MFLOPPY
  893.             if (*(ptr+1) == 'n' || *(ptr+1) == 'N') {
  894.                 saveprompt = FALSE;
  895.             }
  896. # endif
  897.         }
  898. #ifdef    MFLOPPY
  899.         else
  900.             saveprompt = flags.asksavedisk;
  901. #endif
  902.  
  903.         (void) strncpy(SAVEP, bufp, PATHLEN);
  904.         append_slash(SAVEP);
  905. #endif /* MICRO */
  906.     } else if(!strncmpi(buf, "CHARACTER", 4)) {
  907.         (void) strncpy(pl_character, bufp, PL_CSIZ);
  908.     } else if(!strncmpi(buf, "DOGNAME", 3)) {
  909.         (void) strncpy(dogname, bufp, 62);
  910.     } else if(!strncmpi(buf, "CATNAME", 3)) {
  911.         (void) strncpy(catname, bufp, 62);
  912.     } else if(!strncmpi(buf, "NAME", 4)) {
  913.         (void) strncpy(plname, bufp, PL_NSIZ);
  914.         plnamesuffix();
  915.     } else if (!strncmpi(buf, "GRAPHICS", 4)) {
  916.         uchar   translate[MAXPCHARS];
  917.         int   len;
  918.  
  919.         len = get_uchars(fp, buf, bufp, translate,
  920.                     MAXPCHARS, "GRAPHICS");
  921.         assign_graphics(translate, len);
  922.     } else if (!strncmpi(buf, "OBJECTS", 3)) {
  923.         /* oc_syms[0] is the RANDOM object, unused */
  924.         (void) get_uchars(fp, buf, bufp, &(oc_syms[1]),
  925.                     MAXOCLASSES-1, "OBJECTS");
  926.     } else if (!strncmpi(buf, "MONSTERS", 3)) {
  927.         /* monsyms[0] is unused */
  928.         (void) get_uchars(fp, buf, bufp, &(monsyms[1]),
  929.                     MAXMCLASSES-1, "MONSTERS");
  930. #ifdef VIDEOSHADES
  931.     } else if (!strncmpi(buf, "VIDEOCOLORS", 6)) {
  932.         uchar   transcolors[MAXCOLORS];
  933.         int   len;
  934.  
  935.         len = get_uchars(fp, buf, bufp, transcolors,
  936.                     MAXCOLORS, "VIDEOCOLORS");
  937.         assign_videocolors(transcolors, len);
  938.     } else if (!strncmpi(buf, "VIDEOSHADES", 6)) {
  939.         int   len;
  940.  
  941.         len = strlen(bufp);
  942.         assign_videoshades(bufp, len);
  943. #endif
  944. #ifdef AMIGA
  945.     } else if (!strncmpi(buf, "FONT", 4)) {
  946.         char *t;
  947.         extern void amii_set_text_font( char *, int );
  948.  
  949.         if( t = strchr( buf+5, ':' ) )
  950.         {
  951.             *t = 0;
  952.             amii_set_text_font( buf+5, atoi( t + 1 ) );
  953.             *t = ':';
  954.         }
  955.     } else if (!strncmpi(buf, "PATH", 4)) {
  956.         (void) strncpy(PATH, bufp, PATHLEN);
  957. #endif
  958. #ifdef AMIGA
  959.     } else if (!strncmpi(buf, "PENS", 3)) {
  960. # ifdef AMII_GRAPHICS
  961.         int i;
  962.         char *t;
  963.         extern void amii_setpens( void );
  964.  
  965.         for (i = 0, t = strtok(bufp, ",/"); t != NULL;
  966.                     t = strtok(NULL, ",/"), ++i)
  967.         {
  968.             sscanf(t, "%hx", &flags.amii_curmap[i]);
  969.         }
  970.         amii_setpens();
  971. # endif
  972. #endif
  973.     } else
  974.         return 0;
  975.     return 1;
  976. }
  977.  
  978. void
  979. read_config_file(filename)
  980. const char *filename;
  981. {
  982. #define tmp_levels    (char *)0
  983. #define tmp_ramdisk    (char *)0
  984.  
  985. #ifdef MICRO
  986. #undef tmp_levels
  987.     char    tmp_levels[PATHLEN];
  988. # ifdef MFLOPPY
  989. #  ifndef AMIGA
  990. #undef tmp_ramdisk
  991.     char    tmp_ramdisk[PATHLEN];
  992. #  endif
  993. # endif
  994. #endif
  995.     char    buf[BUFSZ];
  996.     FILE    *fp;
  997.  
  998. #ifdef MAC
  999.     long nul = 0L ;
  1000.     Str255 volName ;
  1001.     /*
  1002.      * We should try to get this data from a rsrc, in the profile file
  1003.      * the user double-clicked...  This data should be saved with the
  1004.      * save file in the resource fork, AND be saveable in "stationery"
  1005.      */
  1006.     GetVol ( volName , & theDirs . dataRefNum ) ;
  1007.     GetWDInfo ( theDirs . dataRefNum , & theDirs . dataRefNum , & theDirs .
  1008.         dataDirID , & nul ) ;
  1009.     if ( volName [ 0 ] > 31 ) volName [ 0 ] = 31 ;
  1010.     for ( nul = 1 ; nul <= volName [ 0 ] ; nul ++ ) {
  1011.         if ( volName [ nul ] == ':' ) {
  1012.             volName [ nul ] = 0 ;
  1013.             volName [ 0 ] = nul - 1 ;
  1014.             break ;
  1015.         }
  1016.     }
  1017.     BlockMove ( volName , theDirs . dataName , 32L ) ;
  1018. #endif /* MAC */
  1019.  
  1020.     if (!(fp = fopen_config_file(filename))) return;
  1021.  
  1022. #ifdef MICRO
  1023. # ifdef MFLOPPY
  1024. #  ifndef AMIGA
  1025.     tmp_ramdisk[0] = 0;
  1026. #  endif
  1027. # endif
  1028.     tmp_levels[0] = 0;
  1029. #endif
  1030.  
  1031.     while (fgets(buf, BUFSZ, fp)) {
  1032.         if (!parse_config_line(fp, buf, tmp_ramdisk, tmp_levels)) {
  1033.             raw_printf("Bad option line:  \"%s\"", buf);
  1034.             wait_synch();
  1035.         }
  1036.     }
  1037.     (void) fclose(fp);
  1038.  
  1039. #ifdef MICRO
  1040. # ifdef MFLOPPY
  1041.     Strcpy(permbones, tmp_levels);
  1042. #  ifndef AMIGA
  1043.     if (tmp_ramdisk[0]) {
  1044.         Strcpy(levels, tmp_ramdisk);
  1045.         if (strcmp(permbones, levels))        /* if not identical */
  1046.             ramdisk = TRUE;
  1047.     } else
  1048. #  endif /* AMIGA */
  1049.         Strcpy(levels, tmp_levels);
  1050.  
  1051.     Strcpy(bones, levels);
  1052. # endif /* MFLOPPY */
  1053. #endif /* MICRO */
  1054.     return;
  1055. }
  1056.  
  1057. /* ----------  END CONFIG FILE HANDLING ----------- */
  1058.  
  1059. /* ----------  BEGIN SCOREBOARD CREATION ----------- */
  1060.  
  1061. /* verify that we can write to the scoreboard file; if not, try to create one */
  1062. void
  1063. check_recordfile(dir)
  1064. const char *dir;
  1065. #if defined(applec)
  1066. # pragma unused(dir)
  1067. #endif
  1068. {
  1069. #if defined(UNIX) || defined(VMS)
  1070.     int fd = open(RECORD, O_RDWR, 0);
  1071.  
  1072.     if (fd >= 0) {
  1073. # ifdef VMS    /* must be stream-lf to use UPDATE_RECORD_IN_PLACE */
  1074.         if (!file_is_stmlf(fd)) {
  1075.             raw_printf(    /* note: assume VMS dir has trailing punct */
  1076.           "Warning: scoreboard file %s%s is not in stream_lf format",
  1077.                 (dir ? dir : "[]"), RECORD);
  1078.             wait_synch();
  1079.         }
  1080. # endif
  1081.         (void) close(fd);    /* RECORD is accessible */
  1082.     } else if ((fd = open(RECORD, O_CREAT|O_RDWR, FCMASK)) >= 0) {
  1083.         (void) close(fd);    /* RECORD newly created */
  1084. # if defined(VMS) && !defined(SECURE)
  1085.         /* Re-protect RECORD with world:read+write+execute+delete access. */
  1086.         (void) chmod(RECORD, FCMASK | 007); /* allow everyone full access */
  1087. # endif /* VMS && !SECURE */
  1088.     } else {
  1089.         raw_printf("Warning: cannot write scoreboard file %s/%s",
  1090.             (dir ? dir : "."), RECORD);
  1091.         wait_synch();
  1092.     }
  1093. #endif  /* !UNIX && !VMS */
  1094.  
  1095. #ifdef MICRO
  1096.     int fd;
  1097.     char tmp[PATHLEN];
  1098.  
  1099. # ifdef OS2_CODEVIEW   /* explicit path on opening for OS/2 */
  1100.     Strcpy(tmp, dir);
  1101.     append_slash(tmp);
  1102.     Strcat(tmp, RECORD);
  1103. # else
  1104.     Strcpy(tmp, RECORD);
  1105. # endif
  1106.  
  1107.     if ((fd = open(tmp, O_RDWR)) < 0) {
  1108.         /* try to create empty record */
  1109. # ifdef AZTEC_C
  1110.         /* Aztec doesn't use the third argument */
  1111.         if ((fd = open(tmp, O_CREAT|O_RDWR)) < 0) {
  1112. # else
  1113.         if ((fd = open(tmp, O_CREAT|O_RDWR, S_IREAD|S_IWRITE)) < 0) {
  1114. # endif
  1115.         raw_printf("Warning: cannot write record %s", tmp);
  1116.         wait_synch();
  1117.         } else
  1118.         (void) close(fd);
  1119.     } else        /* open succeeded */
  1120.         (void) close(fd);
  1121. #else /* MICRO */
  1122.  
  1123. # ifdef MAC
  1124.     int fd = macopen ( RECORD , O_RDWR | O_CREAT , TEXT_TYPE ) ;
  1125.  
  1126.     if ( fd < 0 ) {
  1127.         raw_printf ( "Warning: cannot write %s" , RECORD ) ;
  1128.     } else {
  1129.         close ( fd ) ;
  1130.     }
  1131. # endif /* MAC */
  1132.  
  1133. #endif /* MICRO */
  1134. }
  1135.  
  1136. /* ----------  END SCOREBOARD CREATION ----------- */
  1137.  
  1138.  
  1139. /*files.c*/
  1140.